
package control;

import controladoresJpa.exceptions.IllegalOrphanException;
import controladoresJpa.exceptions.NonexistentEntityException;
import excecoes.KeyException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.AssociacaoTabelaAtributo;
import model.AtributoMER;
import model.AtributoMR;
import model.DicionarioMR;
import model.Entidade;
import model.Esquema;
import model.Relacionamento;
import model.Tabela;
import service.AssociacaoTabelaAtributoService;
import service.AtributoMERService;
import service.AtributoMRService;
import service.DicionarioMRService;
import service.EntidadeService;
import service.EsquemaService;
import service.RelacionamentoService;
import service.TabelaService;


/**
 * Classe controladora para o módulo do dicionario para o Modelo Relacional
 * @author Eduardo, Maylon e Kamilla
 */
public class MRController implements Serializable{

    
    private TabelaService ts;
    private AtributoMRService amrs;
    private AtributoMERService amers;
    private DicionarioMRService ds;
    private AssociacaoTabelaAtributoService atas;
    private EsquemaService es;
    private EntidadeService ents;
    private RelacionamentoService rs;
    private static Logger log = Logger.getLogger(ManagementController.class.getName());
    
    /**
     * Método Construtor
     */        
    public MRController() {
        ts = new TabelaService();
        amrs = new AtributoMRService();
        amers = new AtributoMERService();
        ds = new DicionarioMRService();
        atas = new AssociacaoTabelaAtributoService();
        es = new EsquemaService();
        ents = new EntidadeService();
        rs = new RelacionamentoService();
    }

    /**
     * Controla o  processo de salvar um atributo
     * @param atributo
     * @param esquema 
     */
    public void salvarAtributo(AtributoMR atributo, Esquema esquema){
        Esquema e = es.recuperarDoBancoDados(esquema);
        AtributoMR a = amrs.recuperarDoBancoDados(atributo);
        if(e!=null){
            if(a==null){//Se o atributo for nulo, ele será salva e associado ao dicionario do esquema passado como parâmetro.
                amrs.salvar(atributo);
                List list = e.getDicionarioMRList();
                Iterator i = list.iterator();
                while(i.hasNext() ){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    ddmr.getAtributoMRList().add(atributo);
                    atributo.getDicionarioMRList().add(ddmr);
                    ds.salvar(ddmr);
                    amrs.salvar(atributo);
                    log.fine("Novo Atributo: "+ atributo.getNome()+" salvo com sucesso");
                }
            }
            else{//Se o atributo ja existir...
                List list = e.getDicionarioMRList();
                Iterator i = list.iterator();
                while(i.hasNext()){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    if(this.estaAssociado(a, ddmr)){//E estiver associado a algum dicionario do esquema, salvar alterações.              
                        amrs.salvar(a);
                        log.fine("Alteração Atributo: "+ a.getNome()+" salvo com sucesso");
                    }
                    else{//Se nao estiver associado nenhum dicionario desse esquema, associar ao esquema!
                        ddmr.getAtributoMRList().add(a);
                        a.getDicionarioMRList().add(ddmr);
                        ds.salvar(ddmr);
                        amrs.salvar(a);
                        log.fine("Associação Atributo: "+ a.getNome()+" ao esquema");
                    }
                }
            }
        }
    }
    
    /**
     * Controla o  processo de salvar uma Tabela em um esquema
     * @param tabela
     * @param esquema 
     */
    public void salvarTabela(Tabela tabela, Esquema esquema) {
        Esquema e = es.recuperarDoBancoDados(esquema);
        Tabela a = ts.recuperarDoBancoDados(tabela);
        if(e!=null){
            if(a==null){//Se a tabela for nula, ela será salva e associado ao dicionario do esquema passado como parâmetro.
                ts.salvar(tabela);
                List list = e.getDicionarioMRList();
                Iterator i = list.iterator();
                while(i.hasNext() ){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    ddmr.getTabelaList().add(tabela);
                    tabela.getDicionarioMRList().add(ddmr);
                    ds.salvar(ddmr);
                    ts.salvar(tabela);
                    log.fine("Nova Tabela: "+ a.getNome()+" salvo com sucesso");
                }
            }
            else{//Se a tabela ja existir...
                List list = e.getDicionarioMRList();
                Iterator i = list.iterator();
                while(i.hasNext()){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    if(this.estaAssociado(a, ddmr)){//E estiver associado a algum dicionario do esquema, salvar alterações.              
                        ts.salvar(a);
                        log.fine("Alteração Tabela: "+ a.getNome()+" salvo com sucesso");
                    }
                    else{//Se nao estiver associado nenhum dicionario desse esquema, associar ao esquema!
                        ddmr.getTabelaList().add(a);
                        a.getDicionarioMRList().add(ddmr);
                        ds.salvar(ddmr);
                        ts.salvar(a);
                        log.fine("Associação Tabela: "+ a.getNome()+" ao esquema");
                    }
                }
            }
        }
    }
    
/**
     * Controla o  processo de salvar uma Tabela com vários atributos
     * @param tabela
     * @param atributo
     * @param primaria
     * @param candidata
     * @param estrangeira
     * @param esquema 
     */
    public void salvarTabela(Tabela tabela,AtributoMR atributo, boolean primaria, boolean candidata, boolean estrangeira, Esquema esquema) {
        Esquema e = es.recuperarDoBancoDados(esquema);
        Tabela t = ts.recuperarDoBancoDados(tabela);
        if(e!=null){
            if(t==null){//Se a tabela for nula, ela será salva e associado ao dicionario do esquema passado como parâmetro.
                ts.salvar(tabela);
                List list = e.getDicionarioMRList();
                Iterator i = list.iterator();
                while(i.hasNext() ){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    ddmr.getTabelaList().add(tabela);
                    tabela.getDicionarioMRList().add(ddmr);
                    ds.salvar(ddmr);
                    ts.salvar(tabela);
                    //log.fine("Nova Tabela: "+ tabela.getNome()+" salvo com sucesso");
                    //log colocado no métode de TabelaService
                }
                AssociacaoTabelaAtributo associacao = null;
                try {
                    associacao = new AssociacaoTabelaAtributo(tabela, atributo, primaria, estrangeira, candidata);
                } catch (KeyException ex) {
                    Logger.getLogger(MRController.class.getName()).log(Level.SEVERE, null, ex);
                }
                atas.salvar(associacao);
            }
            else{//Se a tabela ja existir...
                List list = e.getDicionarioMRList();
                Iterator i = list.iterator();
                while(i.hasNext()){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    if(this.estaAssociado(t, ddmr)){//E estiver associado a algum dicionario do esquema, salvar alterações.              
                        ts.salvar(t);
                        AssociacaoTabelaAtributo associacao = null;
                        try {
                            associacao = new AssociacaoTabelaAtributo(t, atributo, primaria, estrangeira, candidata);
                        } catch (KeyException ex) {
                            Logger.getLogger(MRController.class.getName()).log(Level.SEVERE, null, ex);
                        }
                        atas.salvar(associacao);
                    }
                    else{//Se nao estiver associado nenhum dicionario desse esquema, associar ao esquema!
                        ddmr.getTabelaList().add(t);
                        t.getDicionarioMRList().add(ddmr);
                        ds.salvar(ddmr);
                        ts.salvar(t);
                        AssociacaoTabelaAtributo associacao = null;
                        try {
                            associacao = new AssociacaoTabelaAtributo(t, atributo, primaria, estrangeira, candidata);
                        } catch (KeyException ex) {
                            Logger.getLogger(MRController.class.getName()).log(Level.SEVERE, null, ex);
                        }
                        atas.salvar(associacao);
                    }
                }
            }
        }
    }
      
/**
     * Controla o  processo de salvar uma tabela
     * @param tabela
     * @param atributos
     * @param esquema 
     */
    public void salvarTabela(Tabela tabela,List atributos, Esquema esquema) {
        Esquema e = es.recuperarDoBancoDados(esquema);
        Tabela t = ts.recuperarDoBancoDados(tabela);
        if(e!=null){
            if(t==null){//Se a tabela for nula, ela será salva e associado ao dicionario do esquema passado como parâmetro.
                ts.salvar(tabela);
                List list = e.getDicionarioMRList();
                Iterator i = list.iterator();
                while(i.hasNext() ){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    ddmr.getTabelaList().add(tabela);
                    tabela.getDicionarioMRList().add(ddmr);
                    ds.salvar(ddmr);
                    ts.salvar(tabela);
                }
                list.iterator();
                        i = atributos.iterator();
                        while(i.hasNext()){
                            AtributoMR atributo = (AtributoMR) i.next();
                            AssociacaoTabelaAtributo associacao = new AssociacaoTabelaAtributo(tabela, atributo);
                            atas.salvar(associacao);
                        }
            }
            else{//Se a tabela ja existir...
                List list = e.getDicionarioMRList();
                Iterator i = list.iterator();
                while(i.hasNext()){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    if(this.estaAssociado(t, ddmr)){//E estiver associado a algum dicionario do esquema, salvar alterações.              
                        ts.salvar(t);
                        list.iterator();
                        i = atributos.iterator();
                        while(i.hasNext()){
                            AtributoMR atributo = (AtributoMR) i.next();
                            AssociacaoTabelaAtributo associacao = new AssociacaoTabelaAtributo(tabela, atributo);
                            atas.salvar(associacao);
                        }
                    }
                    else{//Se nao estiver associado nenhum dicionario desse esquema, associar ao esquema!
                        ddmr.getTabelaList().add(t);
                        t.getDicionarioMRList().add(ddmr);
                        ds.salvar(ddmr);
                        ts.salvar(t);
                        list.iterator();
                        i = atributos.iterator();
                        while(i.hasNext()){
                            AtributoMR atributo = (AtributoMR) i.next();
                            AssociacaoTabelaAtributo associacao = new AssociacaoTabelaAtributo(tabela, atributo);
                            atas.salvar(associacao);
                        }
                    }
                }
            }
        }
    }
    
    /**
     * Verifica se um atributo está contido em um dicionário.
     * @param atributo atributo do modelo relacional.
     * @param ddmr dicionário do modelo relacional.
     * @return valor lógico
     */
    private boolean estaAssociado(AtributoMR atributo, DicionarioMR ddmr){
        List list = ddmr.getAtributoMRList();
        Iterator i = list.iterator();
        while(i.hasNext()){
            AtributoMR a = (AtributoMR)i.next();
            if(a.getNome().equals(atributo.getNome()))
                return true;
        }
        return false;
    }
    
     /**
     * Verifica se uma tabela está contido em um dicionário.
     * @param tabela atributo do modelo relacional.
     * @param ddmr dicionário do modelo relacional.
     * @return valor lógico
     */
    private boolean estaAssociado(Tabela tabela, DicionarioMR ddmr){
        List list = ddmr.getTabelaList();
        Iterator i = list.iterator();
        while(i.hasNext()){
            Tabela a = (Tabela)i.next();
            if(a.getNome().equals(tabela.getNome()))
                return true;
        }
        return false;
    }
    
    
       /**
     * Verifica se um atributo mr está associado a um atributo mer.
     * @param atributoMR atributo do modelo relacional.
     * @param atributoMER atributo do modelo conceitual.
     * @return valor lógico
     */
    private boolean estaAssociado(AtributoMR atributoMR, AtributoMER atributoMER){
        List list = atributoMER.getAtributoMRList();
        Iterator i = list.iterator();
        while(i.hasNext()){
            AtributoMR a = (AtributoMR)i.next();
            if(a.getNome().equals(atributoMR.getNome()))
                return true;
        }
        return false;
    }
    
      /**
     * Verifica se uma tabela está associado a um atributo mer.
     * @param tabela tabela do modelo relacional.
     * @param atributoMER atributo do modelo conceitual.
     * @return valor lógico
     */
    private boolean estaAssociado(Tabela tabela, AtributoMER atributoMER){
        List list = atributoMER.getAtributoMRList();
        Iterator i = list.iterator();
        while(i.hasNext()){
            Tabela a = (Tabela)i.next();
            if(a.getNome().equals(tabela.getNome()))
                return true;
        }
        return false;
    }
    
    /**
     * Verifica se uma tabela está associado a um relacionamento.
     * @param tabela tabela do modelo relacional.
     * @param relacionamento relacionamento do modelo conceitual.
     * @return valor lógico
     */
    private boolean estaAssociado(Tabela tabela, Relacionamento relacionamento){
        List list = relacionamento.getTabelaList();
        Iterator i = list.iterator();
        while(i.hasNext()){
            Tabela a = (Tabela)i.next();
            if(a.getNome().equals(tabela.getNome()))
                return true;
        }
        return false;
    }
    
    
    /**
     * Verifica se uma tabela está associado a uma entidade.
     * @param tabela tabela modelo relacional.
     * @param entidade entidade do modelo conceitual.
     * @return valor lógico
     */
    private boolean estaAssociado(Tabela tabela, Entidade entidade){
        List list = entidade.getTabelaList();
        Iterator i = list.iterator();
        while(i.hasNext()){
            Tabela a = (Tabela)i.next();
            if(a.getNome().equals(tabela.getNome()))
                return true;
        }
        return false;
    }
    
    /**
     * Desassocia um atributo de uma tabela
     * @param tabela
     * @param atributo 
     */
    public void desassociarAtributoTabela(Tabela tabela, AtributoMR atributo) {
        List lst = atas.recarregar();
        Iterator i = lst.iterator();
        while(i.hasNext()){
            AssociacaoTabelaAtributo ata = (AssociacaoTabelaAtributo)i.next();
            if(ata.getNomeatributo().getNome().equals(atributo.getNome())
                    &&ata.getNometabela().getNome().equals(tabela.getNome())){
                atas.excluir(ata);
            }
        }
    }
    
    /**
     * Desassocia um atributo de uma tabela
     * @param tabela
     * @param atributos 
     */
    public void desassociarAtributoTabela(Tabela tabela, List atributos) {  
        Iterator a = atributos.iterator();
        while(a.hasNext()){
            AtributoMR atributo =(AtributoMR)a.next();
            List lst = atas.recarregar();
            Iterator i = lst.iterator();
            while(i.hasNext()){
                AssociacaoTabelaAtributo ata = (AssociacaoTabelaAtributo)i.next();
                if(ata.getNomeatributo().getNome().equals(atributo.getNome())
                        &&ata.getNometabela().getNome().equals(tabela.getNome())){
                    atas.excluir(ata);
                }
            }
        }
    }

    /**
     * Método para exclusão de um atributo
     * @param atributo 
     */
    public void excluirAtributo(AtributoMR atributo) {
            AtributoMR a = amrs.recuperarDoBancoDados(atributo);
            if(a!=null){
                List list = a.getAssociacaoTabelaAtributoList();
                Iterator i = list.iterator();
                while(i.hasNext()){
                    AssociacaoTabelaAtributo associacao = (AssociacaoTabelaAtributo)i.next();
                    atas.excluir(associacao);
                }
                list = a.getDicionarioMRList();
                i = list.iterator();
                //Desfazendo relação entre dicionários e atributos.
                while(i.hasNext()){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                    if(this.estaAssociado(a, ddmr)){
                        ddmr.getAtributoMRList().remove(a);
                        ds.salvar(ddmr);
                    }
                }
                list = a.getAtributoMERList();
                i = list.iterator();
                //Desfazendo relação entre atributo do mr e atributos do mer.
                while(i.hasNext()){
                    AtributoMER amer = (AtributoMER)i.next();
                    if(this.estaAssociado(a, amer)){
                        amer.getAtributoMRList().remove(a);
                        amers.salvar(amer);
                   }
                }
                amrs.excluir(a);
            }
        
    }
    
    /**
     * Método para exclusão de uma Tabela
     * @param tabela 
     */
    public void excluirTabela(Tabela tabela){
            Tabela a = ts.recuperarDoBancoDados(tabela);
            if(a!=null){
                List list = a.getAssociacaoTabelaAtributoList();
                Iterator i = list.iterator();
                while(i.hasNext()){
                    AssociacaoTabelaAtributo associacao = (AssociacaoTabelaAtributo)i.next();
                    atas.excluir(associacao);
                }
                list = a.getDicionarioMRList();
                i = list.iterator();
                //Desfazendo relação entre dicionários e tabelas.
                while(i.hasNext()){
                    DicionarioMR ddmr = (DicionarioMR)i.next();
                   // if(this.estaAssociado(a, ddmr)){
                        ddmr.getTabelaList().remove(a);
                        ds.salvar(ddmr);
                   //}
                }
                list = a.getAtributoMERList();
                i = list.iterator();
                //Desfazendo relação entre tabelas e atributos do mer.
                while(i.hasNext()){
                    AtributoMER amer = (AtributoMER)i.next();
                    if(this.estaAssociado(a, amer)){
                        amer.getTabelaList().remove(a);
                        amers.salvar(amer);
                   }
                }
                list = a.getEntidadeList();
                i = list.iterator();
                //Desfazendo relação entre tabelas e atributos do mer.
                while(i.hasNext()){
                    Entidade amer = (Entidade)i.next();
                    if(this.estaAssociado(a, amer)){
                        amer.getTabelaList().remove(a);
                        ents.salvar(amer);
                   }
                }
                list = a.getRelacionamentoList();
                i = list.iterator();
                //Desfazendo relação entre tabelas e atributos do mer.
                while(i.hasNext()){
                    Relacionamento relacionamento = (Relacionamento)i.next();
                    if(this.estaAssociado(a, relacionamento)){
                        relacionamento.getTabelaList().remove(a);
                        rs.salvar(relacionamento);
                   }
                }
               ts.excluir(a);
            }
        
    }
    
    /**
     * Lista todos os atributos
     * @return 
     */
    public List<AtributoMR> recarregarTodosAtributosMR(){
        return amrs.recarregar();
    }
    
    /**
     * LISTA TODAS AS TABELAS
     * @return 
     */
    public List<Tabela> recarregarTodasTabelas(){
        return ts.recarregar();
    }

    
    /**
     * Recupera os dados de tabelas do BD
     * @param nome
     * @return 
     */
    public Tabela recuperarTabelaDoBancoDados(String nome){
      return ts.recuperarDoBancoDados(new Tabela(nome));
  }
    
    /**
     * Recupera os dados de projetista do BD
     * @param nome
     * @return 
     */
    public AtributoMR recuperarProjetistaDoBancoDados(String nome){
      return amrs.recuperarDoBancoDados(new  AtributoMR(nome));
  }
}
